/** Constructor of Calendar class.
 * @para objectName variable name of Calendar instance.
 * @para mode 0: in place, 1: pop up.
 * @para control the control to store the values after click the dates on the calendar.
 * @para today server's current date, format: yyyy-mm-dd.
 * @para startDate the start available date, format: yyyy-mm-dd.
 * @para takenDate the dates has been purchased,  format: yyyy-mm-dd:yyyy-mm-dd,yyyy-mm-dd:yyyy-mm-dd,yyyy-mm-dd:yyyy-mm-dd....
 * @para clickable true: clickable, false: unclickable
 * @para allClickable true: all clickable, false: depent on conditions
 * @para openPeriod the open accounting period, format: yyyy-mm-dd:yyyy-mm-dd
 */
function Calendar(objectName, mode, control, today, startDate, takenDates, clickable, allClickable, zIndex, openPeriod, selecteDateCallback) {
    this.calendarHolder = null;
    this.monthListHolder = null;
    this.yearListHolder = null;
    this.monthListPlaceHolder = null;
    this.yearListPlaceHolder = null;
    this.objectName = objectName;
    this.control = control;
    this.today = today;
    this.mode = mode;
    this.startDate = startDate;
    this.takenDates = takenDates;
    this.imagePath = theme_path + "/";
    this.selectedDates = new Array();
    this.period = 1;
    this.currentYear = null;
    this.currentMonth = null;
    this.borderFlg = null;
    this.currentYearInYearList = null;
    this.mouseX = null;
    this.mouseY = null;
    this.startX = null;
    this.startY = null;
    this.showFromStart = true;
    this.clickable = (null != clickable) ? clickable : true;
    this.allClickable = (null != allClickable) ? allClickable : false;
    this.zIndex = zIndex;
    this.ie = (null != document.all) ? true : false;
    this.firstAvaialableDate = null;
    this.borderDate = null;
    this.eventSrcElement = null;
    this.openPeriod = openPeriod;
    this.isOpenPeriod = false;
    this.isTheFirst = true;
    this.isTodayAvailable = true;
    this.selecteDateCallback = selecteDateCallback;

    this.weekdays = new Array(sunday, monday, tuesday, wednesday, thursday, friday, saturday);
    this.months = new Array(january, february, march, april, may, june, july, august, september, october, november, december);
    this.init = function() {
        var dayArray = this.today.split("-");
        this.today = this.string2Date(this.today);
        this.startDate = this.string2Date(this.startDate);
        if ("" == this.takenDates) {
            this.takenDates = null;
        }
        this.takenDates = this.setTakenDate(this.takenDates);
        if ("" == this.openPeriod) {
            this.openPeriod = null;
        }
        this.openPeriod = this.getOpenPeriod(this.openPeriod);
        if (1 == this.mode) {
            this.currentYear = this.today.getFullYear();
            this.currentMonth = this.today.getMonth();
            this.currentYearInYearList = this.currentYear;
        }
        else {
            this.currentYear = this.firstAvaialableDate.getFullYear();
            this.currentMonth = this.firstAvaialableDate.getMonth();
            this.currentYearInYearList = this.currentYear;
        }

        var calendarHTML = "<div id=\"calenderHolder\" name=\"calenderHolder\" onclick=\"calendarShow=true\" onmouseover=\"calendarShow=true\" onmouseout=\"calendarShow=false\" style=\"visibility:hidden\"></div><span id=\"monthListHolder\" style=\"position:absolute;visibility:hidden;background-color:#FFFFDD;border:1px solid #EFEFEF;width:65px;cursor:pointer\"></span><span id=\"yearListHolder\" style=\"position:absolute;visibility:hidden;background-color:#FFFFDD;border:1px solid #EFEFEF;width:36px;cursor:pointer\"></span>";
        document.write(calendarHTML);

        this.calendarHolder = document.getElementById("calenderHolder");
        this.monthListHolder = document.getElementById("monthListHolder");
        this.yearListHolder = document.getElementById("yearListHolder");

        if ('undefined' != typeof(this.zIndex)) {
            this.calendarHolder.style.zIndex = this.zIndex;
            this.monthListHolder.style.zIndex = this.zIndex;
            this.yearListHolder.style.zIndex = this.zIndex;
        }

        if (mode == 1) {
            this.calendarHolder.style.position = "absolute";
            this.calendarHolder.style.left = this.control.offsetLeft + 'px';
            this.calendarHolder.style.top = (this.control.offsetTop + this.control.offsetHeight) + 'px';
        }
        else {
            this.show();
        }

        if (this.openPeriod && (this.openPeriod.length > 0)) {
            this.isOpenPeriod = true;
        }
    }

    /**
     * auto adjust calendar position to be sensetive to browser window.
     */
    this.autoCalendarPosition = function() {
        var bodyHeight = document.documentElement.clientHeight;
        var bodyWidth = document.documentElement.clientWidth;
        var scrollBarTop = document.documentElement.scrollTop;
        var scrollBarLeft = document.documentElement.scrollLeft;
        var browserHeight = bodyHeight + scrollBarTop;
        var browserWidth = bodyWidth + scrollBarLeft;
        var calendarHolderWidth = this.calendarHolder.scrollWidth;
        var calenderHolderHeight = this.calendarHolder.scrollHeight;
        var tempX = parseInt(this.startX);
        var tempY = parseInt(this.startY);
        var srcElementTop = 0;

        //adjust herizontal position if the left of the click location
        if ((browserWidth < (tempX + calendarHolderWidth)) && ((tempX - calendarHolderWidth - scrollBarLeft) > 0)) {
            tempX -=  calendarHolderWidth;
        }

        //adjust vertical position
        var element = this.eventSrcElement;
        while (element) {
            srcElementTop += element.offsetTop;
            element = element.offsetParent;
        }
        //if this is the first show, calculate the position for calendar
        if (this.isTheFirst) {
            if (tempY + calenderHolderHeight > browserHeight) {
                if ((tempY - scrollBarTop) > calenderHolderHeight) { //enough space above click location
                    tempY = srcElementTop - calenderHolderHeight;
                }
                else {
                    tempY = scrollBarTop;
                }
            }
            else {
                tempY = srcElementTop + this.eventSrcElement.offsetHeight;
            }

            this.startX = tempX + "px";
            this.startY = tempY + "px";
            this.isTheFirst = false;
        }
    }

    /**
     * Shows the calendar, usually called when to pop up the calendar.
     */
    this.show = function(event) {
        this.hideAllCalendar();
        var calendarHTML = null;
        calendarHTML = "<table style=\"border-collapse:collapse;width:225px;height:165px;font-family:verdana;background-color:#FFFFFF;border:1px solid #EFEFEF\">";
        calendarHTML += this.getHeaderHTML();
        calendarHTML += this.getWeekdaysHTML();
        calendarHTML += this.getDaysHTML();
        calendarHTML += this.getFooterHTML();
        calendarHTML += "</table>";
        if (this.ie) {
            calendarHTML += "<iframe src=\"javascript:false\" style=\"position:absolute;visibility:inherit;top:0px;left:0px;width:225px;height:165px;z-index:-1;filter='progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';\"></iframe>";
        }
        this.hideMonthList();
        this.hideYearList();
        this.calendarHolder.innerHTML = calendarHTML;
        //if this is the first show, change the position of calendar
        if (this.isTheFirst) {
            if (this.showFromStart && (null != event)) {
                this.startX = this.getX(event);
                this.startY = this.getY(event);
                this.getSrcElement(event);
            }
            if (null != this.startX) {
                this.autoCalendarPosition();
                this.calendarHolder.style.left = this.startX;
                this.calendarHolder.style.top = this.startY;
            }
        }
        if (this.ie && (this.calendarHolder.style.left != this.startX)) {
            this.calendarHolder.style.left = this.startX;
        }
        this.showFromStart = true;
        this.calendarHolder.style.visibility = "visible";
        this.monthListPlaceHolder = document.getElementById("monthListPlaceHolder");
        this.yearListPlaceHolder = document.getElementById("yearListPlaceHolder");
        if (mode == 1) {
            document.onclick = function() {
                if (!calendarShow) {
                    var elements = document.getElementsByName("calenderHolder");
                    for(var i = 0; i < elements.length; i++) {
                        elements[i].style.visibility = "hidden";
                    }
                    document.getElementById("monthListHolder").style.visibility = "hidden";
                    document.getElementById("yearListHolder").style.visibility = "hidden";
                }
                calendarShow = false;
            };
            calendarShow = true;
        }
    }

    this.hideAllCalendar = function() {
        var elements = document.getElementsByName("calenderHolder");
        for(var i = 0; i < elements.length; i++) {
            elements[i].style.visibility = "hidden";
        }
    }

    /**
     * Selects a period.
     * @para the day amount to select.
     * @para startDate the start date, format: yyyy-mm-dd.
     */
    this.showPeriod = function(period, startDate) {
        this.period = period.replace(/\,/g,"");
        if (null != startDate) {
            this.onClickDate(startDate, false);
            var tmpDate = this.string2Date(startDate);
            this.onClickMonth(tmpDate.getMonth());
            this.onClickYear(tmpDate.getFullYear());
        }
        else {
            this.onClickDate(this.date2String(this.firstAvaialableDate));
        }
        if (this.mode == 1) {
            this.hide();
        }
    }

    this.hide = function() {
        this.calendarHolder.style.visibility = "hidden";
        this.hideMonthList();
        this.hideYearList();
    }

    this.onDecreaseMonth = function() {
        var date = new Date(this.currentYear, this.currentMonth - 1, 1);
        this.showFromStart = false;
        this.showMonth(date);
    }

    this.onIncreaseMonth = function() {
        var date = new Date(this.currentYear, this.currentMonth + 1, 1);
        this.showFromStart = false;
        this.showMonth(date);
    }

    this.onDecreaseYear = function(event) {
        this.currentYearInYearList -= 1;
        var date = new Date(this.currentYearInYearList, this.currentMonth, 1);
        this.showYearList(null, document.getElementById("yearListClicker"), date);
    }

    this.onIncreaseYear = function(event) {
        this.currentYearInYearList += 1;
        var date = new Date(this.currentYearInYearList, this.currentMonth - 1, 1);
        this.showFromStart = false;
        this.showYearList(null, document.getElementById("yearListClicker"), date);
    }

    this.onClickToday = function() {
        this.showFromStart = false;
        this.showMonth(this.today);
    }

    this.onClickDate = function(day, callBack) {
        var date = this.string2Date(day);
        var callBackFun = ('undefined' == typeof callBack) ? true : callBack;
        this.selectedDates = this.selectPeriod(date, this.period);
        this.show();
        if (null != this.control) {
            this.control.value = this.dateArray2String(this.selectedDates);
            try {
                this.control.onchange();
            }
            catch (e) {
                //empty
            }
        }
        if (this.mode == 1) {
            this.hide();
        }
        if (callBackFun && this.selecteDateCallback && typeof (this.selecteDateCallback == "function")) {
            selecteDateCallback();
        }

    }

    /**
     * Selects run dates.
     * @para the day amount to select.
     */
    this.selectRunDates = function(runDates) {
        this.selectedDates = this.string2dateArray(runDates);
        var periodArray = runDates.split(":");
        this.borderDate = this.string2Date(periodArray[0]);
        this.onClickMonth(this.borderDate.getMonth());
        this.onClickYear(this.borderDate.getFullYear());
        this.show();
    }

    this.onClickMonth = function(month) {
        var date = new Date(this.currentYear, month, 1);
        this.showFromStart = false;
        this.showMonth(date);
        this.hideMonthList();
    }

    this.onClickYear = function(year) {
        var date = new Date(year, this.currentMonth, 1);
        if (this.isOpenPeriod && !this.isInOpenPeriod(date)) {
            date = this.openPeriod[0].startDay;
        }

        this.showFromStart = false;
        this.showMonth(date);
        this.hideYearList();
    }

    this.showMonth = function(date) {
        this.currentYear = date.getFullYear();
        this.currentMonth = date.getMonth();
        this.show();
    }

    this.showMonthList = function(event, placeHolder) {
        if (null != event) {
            this.mouseX = this.getX(event);
            this.mouseY = this.getY(event);
        }

        this.monthListHolder.style.left = this.mouseX;
        this.monthListHolder.style.top = this.mouseY;
        this.monthListHolder.innerHTML = this.getMonthListHTML();
        this.hideYearList();
        this.monthListHolder.style.visibility = "visible";
    }

    this.hideMonthList = function() {
        this.monthListHolder.style.visibility = "hidden";
        clearTimeout(timeoutID1);
        clearTimeout(timeoutID2);
    }

    this.showYearList = function(event, placeHolder, date) {
        if (null == date) {
            date = new Date(this.currentYear, this.currentMonth, 1);
        }
        if (null != event) {
            this.mouseX = this.getX(event);
            this.mouseY = this.getY(event);
        }
        this.yearListHolder.style.left = this.mouseX;
        this.yearListHolder.style.top = this.mouseY;
        this.yearListHolder.innerHTML = this.getYearListHTML(date);
        this.hideMonthList();
        this.yearListHolder.style.visibility = "visible";
    }

    this.hideYearList = function() {
        this.currentYearInYearList = this.currentYear;
        this.yearListHolder.style.visibility = "hidden";
        clearTimeout(timeoutID1);
        clearTimeout(timeoutID2);
    }

    this.setImageSource = function(image, imageName){
        image.setAttribute("src", this.imagePath + imageName);
    }

    this.getHeaderHTML = function() {
        var cols = 7;
        if (1 == mode) {
            cols = 6;
        }

        var lastMonth = new Date(this.currentYear, this.currentMonth - 1, 1);
        var lastDate = new Date(this.currentYear, this.currentMonth, 0);
        var headerHTML = "<tr><td><table align=\"center\" width=\"100%\" style=\"border-collapse:collapse\">";
        headerHTML += "<tr style=\"height:18px;background-color:#42b2c0;font:bold 11px Arial sans-serif;color:#FFFFFF\"><td colspan=\"" + cols + "\" style=\"padding:3px;text-align:left;\">";
        if (this.isOpenPeriod && !(this.isInOpenPeriod(lastMonth) || this.isInOpenPeriod(lastDate))) {
            headerHTML += "<span><span style=\"border:3px solid #42b2c0;\">";
            headerHTML += "&nbsp;<img style='width:10px;height:11px' src='" + this.imagePath + "arrow-left-dark.gif')\"/>&nbsp;</a></span>&nbsp;";
        }
        else {
            headerHTML += "<span><span style=\"border:3px solid #42b2c0;cursor:pointer\"><a onclick=\"" + this.objectName + ".onDecreaseMonth()\">";
            headerHTML += "&nbsp;<img style='width:10px;height:11px' src='" + this.imagePath + "arrow-left-dark.gif' onmouseover=\""+ this.objectName +".setImageSource(this, 'arrow-left-bright.gif')\" onmouseout=\""+ this.objectName +".setImageSource(this, 'arrow-left-dark.gif')\"/>&nbsp;</a></span>&nbsp;";
        }
        headerHTML += "<span style=\"border:3px solid #42b2c0;cursor:pointer\"><a onclick=\"" + this.objectName + ".onIncreaseMonth()\">";
        headerHTML += "&nbsp;<img style='width:10px;height:11px' src='" + this.imagePath + "arrow-right-dark.gif' onmouseover=\""+ this.objectName +".setImageSource(this, 'arrow-right-bright.gif')\" onmouseout=\""+ this.objectName +".setImageSource(this, 'arrow-right-dark.gif')\"/>&nbsp;</a></span>&nbsp;";
        headerHTML += "<span style=\"border:3px solid #42b2c0;cursor:pointer\"><a onmouseover=\"this.style.color='#FFFFFF'\" onmouseout='clearTimeout(timeoutID1);timeoutID1=setTimeout(\"" + this.objectName + ".hideMonthList()\",100);event.cancelBubble=true' onclick=\"" + this.objectName + ".showMonthList(event, this)\" style=\"font-weight:bold\">&nbsp;" + this.months[this.currentMonth];
        headerHTML += "<img src='" + this.imagePath + "arrow-down-dark.gif' onmouseover=\""+ this.objectName +".setImageSource(this, 'arrow-down.gif')\" onmouseout=\""+ this.objectName +".setImageSource(this, 'arrow-down-dark.gif')\"/></a></span>";
        headerHTML += "<span id=\"monthListPlaceHolder\"></span>&nbsp;";
        headerHTML += "<span id=\"yearListClicker\" style=\"border:3px solid #42b2c0;cursor:pointer\"><a onmouseover=\"this.style.color='#FFFFFF';\" onmouseout='clearTimeout(timeoutID2);timeoutID2=setTimeout(\"" + this.objectName + ".hideYearList()\",100);event.cancelBubble=true' onclick=\"" + this.objectName + ".showYearList(event, this)\" style=\"font-weight:bold\">&nbsp;" + this.currentYear;
        headerHTML += "<img src='" + this.imagePath + "arrow-down-dark.gif' onmouseover=\""+ this.objectName +".setImageSource(this, 'arrow-down.gif')\" onmouseout=\""+ this.objectName +".setImageSource(this, 'arrow-down-dark.gif')\"/></a></span>";
        headerHTML += "<span id=\"yearListPlaceHolder\"></span></td>";
        if (1 == mode) {
            headerHTML += "<td cellspacing=\"0\" style=\"text-align:right\"><a href='javascript:" + this.objectName + ".hideAllCalendar()'><img src='"+this.imagePath+"close.gif' style=\"width:15px;height:13px;border:none\" alt='Close the Calendar'></a></td>";
        }
        headerHTML += "</tr></table></td></tr>";
        return  headerHTML;
    }

    this.getFooterHTML = function() {
        textTodayIs = textTodayIs.replace('<day>', this.weekdays[this.today.getDay()]);
        textTodayIs = textTodayIs.replace('<month>', this.months[this.today.getMonth()]);
        textTodayIs = textTodayIs.replace('<date>', this.today.getDate());
        textTodayIs = textTodayIs.replace('<year>', this.today.getFullYear());
        return "<tr><td><table width=\"100%\" align=\"center\"><tr style=\"background-color:#DDDDDD;font-size:11px;height:20px;\"><td colspan=\"7\" style=\"text-align:center\"><a href=\"javascript:" + this.objectName + ".onClickToday()\" title=\"Go To Current Month\" style=\"color:#000000\">" + textTodayIs + "</a></td></tr></table></td></tr>";
    }

    this.getMonthListHTML = function() {
        var monthListHTML = "<div style='text-align:center;' onmouseover='clearTimeout(timeoutID1)' onmouseout='clearTimeout(timeoutID1);timeoutID1=setTimeout(\"" + this.objectName + ".hideMonthList()\",100);event.cancelBubble=true'>";
        for (var i in this.months) {
            var monthName = this.months[i];
            var thisMonth = new Date (this.currentYear, i, 1);
            var lastDate = new Date(this.currentYear, parseInt(i)+1, 0);
            if (i==this.currentMonth){
                monthName = "<span style=\"font-weight:bold\">" + monthName + "</span>"
            }
            if (this.isOpenPeriod && !(this.isInOpenPeriod(thisMonth) || this.isInOpenPeriod(lastDate))) {
                monthListHTML += "<div style=\"padding:1px;text-align:left;font-size:11px;color:#909090\" onclick=\"event.cancelBubble=true\">&nbsp;" + monthName + "</div>"
            }
            else {
                monthListHTML += "<div onmouseover='this.style.backgroundColor=\"#FFCC99\"' onmouseout='this.style.backgroundColor=\"\"' onclick=\"" + this.objectName + ".onClickMonth(" + i + ")\" style=\"padding:1px;text-align:left;font-size:11px\">&nbsp;" + monthName + "</div>";
            }
        }
        if (this.ie) {
            monthListHTML += "<iframe src=\"javascript:false\" style=\"position:absolute;visibility:inherit;top:0px;left:0px;width:65px;height:200px;z-index:-1;filter='progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';\"></iframe>";
        }
        monthListHTML += "</div>"
        return monthListHTML;
    }

    this.getYearListHTML = function(date) {
        var yearListHTML = "<div onmouseover='clearTimeout(timeoutID2)' onmouseout='clearTimeout(timeoutID2);timeoutID2=setTimeout(\"" + this.objectName + ".hideYearList()\",100);event.cancelBubble=true'>";
        if (!this.openPeriod ||
            this.openPeriod.length <= 0) {
            yearListHTML += "<div onclick=\"" + this.objectName + ".onDecreaseYear(event, " + i + ")\" style=\"padding:1px;text-align:center;font-size:11px\">&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;&nbsp;&nbsp;&nbsp;</div>";
        }
        for (var i = date.getFullYear() - 5; i < date.getFullYear() + 5; i++) {
            var yearName = i;
            if (i == this.currentYear){
                yearName =  "<span style=\"font-weight:bold\">" + yearName + "</span>"
            }
            var thisYearDay = new Date(parseInt(i), 11, 31);
            if (this.isOpenPeriod && !this.isInOpenPeriod(thisYearDay)) {
                yearListHTML += "<div  style=\"padding:1px;text-align:center;font-size:11px;color:#909090\" onclick=\"event.cancelBubble=true\">&nbsp;" + yearName + "</div>";
            }
            else {
                yearListHTML += "<div onmouseover='this.style.backgroundColor=\"#FFCC99\"' onmouseout='this.style.backgroundColor=\"\"' onclick=\"" + this.objectName + ".onClickYear(" + i + ")\" style=\"padding:1px;text-align:center;font-size:11px\">&nbsp;" + yearName + "</div>";
            }
        }
        yearListHTML += "<div onclick=\"" + this.objectName + ".onIncreaseYear(event, " + i + ")\" style=\"padding:1px;text-align:center;font-size:11px\">&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;&nbsp;&nbsp;&nbsp;</div>";
        if (this.ie) {
            yearListHTML += "<iframe src=\"javascript:false\" style=\"position:absolute;visibility:inherit;top:0px;left:0px;width:40px;height:200px;z-index:-1;filter='progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';\"></iframe>";
        }
        yearListHTML += "</div>"
        return yearListHTML;
    }

    this.getWeekdaysHTML = function() {
        var weekdaysHTML = null;
        weekdaysHTML = "<tr><td><table align=\"center\" style=\"margin:7px\"><tr style=\"font-size:11px\">";
        for (var i in this.weekdays) {
            weekdaysHTML += "<td style=\"width:27px;text-align:right\"><span style=\"font-weight:bold\">" + this.weekdays[i] + "</span></td>";
        }
        weekdaysHTML += "</tr>";
        return weekdaysHTML;
    }

    this.getDaysHTML = function() {
        var daysHTML = null;
        var end = false;
        var lastDate = new Date(this.currentYear, this.currentMonth + 1, 0);
        var totalDays = lastDate.getDate();
        var startDay = new Date(this.currentYear, this.currentMonth, 1);
        var weekDay = startDay.getDay();
        var day = startDay.getDate() - weekDay;
        this.borderFlg = true;
        daysHTML = "";
        for (var i = 0; (i < 6) && (!end); i++) {
            daysHTML += "<tr style=\"font-size:11px\">";
            for (var j = 0; j < 7; j++) {
                if ((day > 0) && (day <= totalDays)) {
                    var date = new Date(this.currentYear, this.currentMonth, day);
                    daysHTML += this.getDayCellHTML(date);
                }
                else {
                    daysHTML += "<td>&nbsp;</td>";
                }
                end = (day >= totalDays);
                day++;
            }
            daysHTML += "</tr>";
        }
        daysHTML += "</tr></table></td></tr>";
        return daysHTML;
    }

    this.getDayCellHTML = function(date) {
        var dayCellHTML = "<td style='text-align:center;'>";
        var day = null;
        day = "&nbsp;" + date.getDate() + "&nbsp;";

        if (this.allClickable) {
            if (this.clickable) {
                if (this.isOpenPeriod) {
                    if (this.isInOpenPeriod(date)) {
                        dayCellHTML += "<span style=\"cursor:pointer;color:#000000\"><a onclick=\"" + this.objectName + ".onClickDate('" + this.date2String(date) + "')\">" + day + "</a></span>";
                    }
                    else {
                        dayCellHTML += "<span style=\"color:#909090;\">" + day + "</span>";
                    }
                }
                else {
                    dayCellHTML += "<span style=\"cursor:pointer;color:#000000\"><a onclick=\"" + this.objectName + ".onClickDate('" + this.date2String(date) + "')\">" + day + "</a></span>";
                }
            }
            else {
                dayCellHTML += "<span style=\"color:#000000\">" + day + "</span>";
            }
        }
        else {
           var borderStyle= this.getBorderStyle(date);
           if (this.isToday(date) && !this.isUnavailable(date)) {
                if (this.clickable) {
                    if (this.isOpenPeriod) {
                        if (this.isInOpenPeriod(date)) {
                            dayCellHTML += "<span style=\"" + borderStyle + "cursor:pointer\"><a onclick=\"" + this.objectName + ".onClickDate('" + this.date2String(date) + "')\" style=\"color:#FF0000;font-weight:bold;\">" + day + "</a></span>";
                        }
                        else {
                            dayCellHTML += "<span style=\"text-decoration:line-through\">" + day + "</span>";
                        }
                    }
                    else {
                        dayCellHTML += "<span style=\"" + borderStyle + "cursor:pointer\"><a onclick=\"" + this.objectName + ".onClickDate('" + this.date2String(date) + "')\" style=\"color:#FF0000;font-weight:bold;\">" + day + "</a></span>";
                    }
                }
                else {
                    dayCellHTML += "<span style=\"" + borderStyle + "color:#FF0000;font-weight:bold;\">" + day + "</span>";
                }
           }
           else if (this.isSelected(date)) {
                if (this.clickable) {
                    dayCellHTML += "<span style=\"" + borderStyle + "color:#42b2c0;cursor:pointer;font-weight:bold;\"><a onmouseover=\"this.style.color='#42b2c0'\" onclick=\"" + this.objectName + ".onClickDate('" + this.date2String(date) + "')\">" + day + "</a></span>";
                }
                else {
                    dayCellHTML += "<span style=\"" + borderStyle + "color:#42b2c0;font-weight:bold;\">" + day + "</span>";
                }
            }
            else if (this.isTaken(date)) {
                dayCellHTML += "<span style=\"text-decoration:line-through\">" + day + "</span>";
            }
            else if (this.isUnavailable(date)) {
                dayCellHTML += "<span style=\"color:#909090;font-weight:bold;\">" + day + "</span>";
            }
            else {
                if (this.clickable) {
                    dayCellHTML += "<span style=\"" + borderStyle + "cursor:pointer;color:#000000\"><a onclick=\"" + this.objectName + ".onClickDate('" + this.date2String(date) + "')\">" + day + "</a></span>";
                }
                else {
                    dayCellHTML += "<span style=\"" + borderStyle + "color:#000000\">" + day + "</span>";
                }
            }
        }
        dayCellHTML += "</td>";
        return dayCellHTML;
    }

    this.isSelected = function(date) {
        return this.isInDateArray(date, this.selectedDates);
    }

    this.isUnavailable = function(date) {
        var result;
        if (1 == this.mode) {
            result = (this.isTodayAvailable) ? date < this.today : date <= this.today;
        }
        else {
            result = (date <= this.today) || (date < this.startDate);
        }

        return result;
    }

    this.isTaken = function(date) {
        return this.isInDateArray(date, this.takenDates);
    }

    this.isToday = function(date) {
        return this.dateEquals(date, this.today);
    }

    this.isInDateArray = function(date, dateArray) {
        for (var i in dateArray) {
            if (this.dateEquals(date, dateArray[i])) {
                return true;
            }
        }
        return false;
    }

    this.string2Date = function(dateString) {
        var dateArray = dateString.split("-");
        return new Date(dateArray[0], dateArray[1] - 1, dateArray[2]);
    }

    this.date2String = function(date) {
        var year = date.getFullYear();
        var month = date.getMonth() + 1;
        var day = date.getDate();
        if (month < 10) {
            month = "0" + month;
        }
        if (day < 10) {
            day = "0" + day;
        }
        return year + "-" + month + "-" + day;
    }

    this.dateEquals = function(date, dateToCheck) {
        return ((date - dateToCheck) == 0);
    }

    this.selectPeriod = function(date, period) {
        var datesArray = new Array();
        var currentDate = date;
        var count=0;
        if (!this.allClickable) {
            for (var i = 0; i < period; i++) {
                while (this.isTaken(currentDate) || this.isUnavailable(currentDate)) {
                    currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() + 1);
                }
                datesArray[i] = currentDate;
                currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() + 1);
            }
        }
        else {
            datesArray[0] = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate());
        }
        return datesArray;
    }

    this.string2dateArray = function(datesString) {
        var dateArray = new Array();
        var count = 0;
        var periodArray = new Array();
        if (null != datesString) {
            periodArray = datesString.split(",");
        }
        for (var i in periodArray) {
            var dates = periodArray[i].split(":");
            for (var date = this.string2Date(dates[0]); date <= this.string2Date(dates[1]); date = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1)) {
                dateArray[count++] = date;
            }
        }
        return dateArray;
    }

    this.setTakenDate = function(takenDate) {
        var dateArray = new Array();
        var count = 0;
        var periodArray = new Array();
        if (null != takenDate) {
            periodArray = takenDate.split(",");
        }
        var flg = true;
        var tomorrow = new Date(this.today.getFullYear(), this.today.getMonth(), this.today.getDate() + 1);
        var startDate = (this.startDate > tomorrow) ? this.startDate : tomorrow
        this.firstAvaialableDate = startDate;
        for (var i in periodArray) {
            var dates = periodArray[i].split(":");
            var newDate;
            var firstDate;
            for (firstDate = newDate = this.string2Date(dates[0]); newDate <= this.string2Date(dates[1]); newDate = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate() + 1)) {
                dateArray[count++] = newDate;
            }
            if (flg) {
                if (startDate >= firstDate && newDate >= startDate) {
                    var date = dateArray[dateArray.length - 1];
                    this.firstAvaialableDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1)
                    flg = false;
                }
                else if (firstDate > startDate) {
                    flg = false;
                }
            }
        }
        return dateArray;
    }

    /**
     * Checks the day whether in the open period.
     * @para date day
     * @return boolean
     */
    this.isInOpenPeriod = function(day) {
        for (var i in this.openPeriod) {
            if ((day >= this.openPeriod[i].startDay) &&
                ((day <= this.openPeriod[i].endDay) ||
                  (this.date2String(this.string2Date('0000-00-00')) == this.date2String(this.openPeriod[i].endDay)))) {
                return true;
            }
        }

        return false;
    }

    /**
     * Gets open period array.
     * @para string openPeriod
     * @return array
     */
    this.getOpenPeriod = function(openPeriod) {
        var openPeriodArray = new Array();
        var periodArray = new Array();
        if (null != openPeriod && "" != openPeriod) {
            periodArray = openPeriod.split(",");
        }
        for (var i in periodArray) {
            var dates = periodArray[i].split(":");
            period = {'startDay':this.string2Date(dates[0]), 'endDay':this.string2Date(dates[1])};
            openPeriodArray[i] = period;
        }

        return openPeriodArray;
    }

    this.dateArray2String = function(dateArray) {
        var count = 0;
        var start = true;
        var datesString = '';
        for (var i = 0; i < dateArray.length; i++) {
            if (datesString == '') {
                datesString += this.date2String(dateArray[i]);
            }
            else {
                var lastDay = dateArray[i - 1];
                var secondDay = new Date(lastDay.getFullYear(), lastDay.getMonth(), lastDay.getDate() + 1);
                if (!this.dateEquals(secondDay, dateArray[i])) {
                    datesString += ":" + this.date2String(lastDay);
                    datesString += "," + this.date2String(dateArray[i]);
                }
                if (dateArray.length == (i + 1)) {
                    datesString += ":" + this.date2String(dateArray[i]);
                }
            }
        }
        return datesString;
    }

    this.getSrcElement = function(event) {
        var e = event || window.event;
        this.eventSrcElement = (!!document.all) ? e.srcElement : e.target;
    }

    this.getX = function(event){
        var e = event || window.event;
        var x = e.pageX || e.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft);
        this.mouseX = x;
        return (parseInt(x/10) * 10 - 10) + "px";
    }

    this.getY = function(event){
        var e = event || window.event;
        var y = e.pageY || e.clientY + (document.body.scrollTop || document.documentElement.scrollTop);
        this.mouseY = y;
        return (parseInt(y/10) * 10 + 10) + "px";
    }

    this.getBorderStyle = function(date){
        var borderStyle = '';
        if (null != this.borderDate){
            if (this.dateEquals(date, this.borderDate)) {
                return 'border:1px solid #A0A0A0;';
            }
        }
        else {
            if (1 == this.mode) {
                if ((0 < this.selectedDates.length) && this.isSelected(date) && this.borderFlg) {
                    borderStyle = 'border:1px solid #A0A0A0;';
                    this.borderFlg = false;
                }
                else if ((0 == this.selectedDates.length) && this.isToday(date) && this.borderFlg){
                    borderStyle = 'border:1px solid #A0A0A0;';
                    this.borderFlg = false;
                }
            }
            else {
                 var startYear = this.firstAvaialableDate.getFullYear();
                 var startMonth = this.firstAvaialableDate.getMonth();
                 var lastDate = new Date(startYear, startMonth + 1, 0);
                 if ((date >= this.firstAvaialableDate) && (lastDate >= date) && this.borderFlg) {
                    if (false == this.isTaken(date)) {
                       borderStyle = 'border:1px solid #A0A0A0;';
                       this.borderFlg = false;
                    }
                 }
            }
        }

        return borderStyle;
    }

    this.init();
}
var calendarShow = true;
var timeoutID1;
var timeoutID2;